
#include <BMap>
#include <BLabel>
#include <BButton>
#include <BGridLayout>
#include <BVBoxLayout>
#include <BScrollWidget>

#include "ScriptPropertyDialog.h"

ScriptPropertyDialog::ScriptPropertyDialog(BWidget* parent) : BDialog(parent)
{
	this->setTitle("Script Property");

	BWidget* settingWidget = new BWidget();
	settingWidget->setTitle("Setting");
	{
		BGridLayout* gridLayout = new BGridLayout();
		{
			_targetEdit = new BLineEdit();
			_pathEdit = new BLineEdit();
			_fileNameEdit = new BLineEdit();

			gridLayout->addWidget(0, 0, new BLabel("target"));
			gridLayout->addWidget(0, 1, _targetEdit);
			gridLayout->addWidget(1, 0, new BLabel("path"));
			gridLayout->addWidget(1, 1, _pathEdit);
			gridLayout->addWidget(2, 0, new BLabel("file"));
			gridLayout->addWidget(2, 1, _fileNameEdit);
			gridLayout->setColumnPolicy(0, Policy_Preferred);
		}

		_includePathWidget = new BListWidget("include paths");
		_includePathWidget->setTitleVisible(true);
		_includePathWidget->setAreaPolicy(Policy_Preferred | Policy_Dynamic, Policy_Preferred);

		_importPathWidget = new BListWidget("import paths");
		_importPathWidget->setTitleVisible(true);
		_importPathWidget->setAreaPolicy(Policy_Preferred | Policy_Dynamic, Policy_Preferred);

		_itemEdit = new BLineEdit(this);
		_browseButton = new BButton("...", _itemEdit);
		_browseButton->setName("browse");
		_itemEdit->hide();

		BVBoxLayout* vlayout = new BVBoxLayout(settingWidget);
		vlayout->addLayout(gridLayout);
		vlayout->addWidget(_includePathWidget);
		vlayout->addWidget(_importPathWidget);
		vlayout->addSpring();
	}

	_treeWidget = new BTreeWidget();
	_treeWidget->setAreaPolicy(Policy_Growing, Policy_Preferred);
	_treeWidget->setTitle("Property");

	_tabWidget = new BTabWidget();
	_tabWidget->addTab(settingWidget);
	_tabWidget->addTab(_treeWidget);

	BLayout* layout = new BLayout(this);
	layout->setWidget(_tabWidget);

	connect(this, Signal_AssetChanged, &ScriptPropertyDialog::slotAssetChanged);

	connect(_includePathWidget, Signal_ItemClicked, &ScriptPropertyDialog::slotListItemClicked);
	connect(_importPathWidget, Signal_ItemClicked, &ScriptPropertyDialog::slotListItemClicked);
	connect(_targetEdit, Signal_EditFinished, &ScriptPropertyDialog::slotTargetEditFinished);
	connect(_itemEdit, Signal_EditFinished, &ScriptPropertyDialog::slotItemEditFinished);
	connect(_itemEdit, Signal_Actived, &ScriptPropertyDialog::slotItemEditActived);
	connect(_browseButton, Signal_Clicked, &ScriptPropertyDialog::slotBrowseButtonClicked);

}
ScriptPropertyDialog::~ScriptPropertyDialog()
{

}

void ScriptPropertyDialog::applyIncludePaths()
{
	_script->clearIncludePaths();
	for (int i = 0; i < _includePathWidget->itemCount(); i++)
	{
		BListItem* item = _includePathWidget->item(i);
		const BString& text = item->text();
		if (text.size())
		{
			_script->insertIncludePath(text);
		}
	}
}
void ScriptPropertyDialog::applyImportPaths()
{
	_script->clearImportPaths();
	for (int i = 0; i < _importPathWidget->itemCount(); i++)
	{
		BListItem* item = _importPathWidget->item(i);
		const BString& text = item->text();
		if (text.size())
		{
			_script->insertImportPath(text);
		}
	}
}
BTreeItem* ScriptPropertyDialog::createTreeItem(BClass* cls)
{
	BTreeItem* item = new BTreeItem(cls->name());
	item->setAsset(cls);
	item->setExpanded(false);
	for (int i = 0; i < cls->methodCount(); i++)
	{
		BString name = cls->methodFullName(i);
		item->addChild(name);
	}
	BString type, name, text;
	for (int i = 0; i < cls->variantCount(); i++)
	{
		cls->variant(i, type, name);
		if (type.empty()) type = "void";
		item->addChild(type + ' ' + name);
	}
	return item;
}

void ScriptPropertyDialog::slotAssetChanged(BObject* object, const BValue& value)
{
	BScript* script = value;
	if (_script != script)
	{
		if (_script)
		{
			_treeWidget->clearItems();
		}
		_script = script;
		if (_script)
		{
			const BString& target = _script->property("target");
			_targetEdit->setText(target);
			_pathEdit->setText(_script->path());
			BString fileName;
			fileName << _script->path() << '/' << _script->name();
			_fileNameEdit->setText(fileName);

			_includePathWidget->clearItems();
			for (int i = 0; i < _script->includePathCount(); i++)
			{
				const BString& path = _script->includePath(i);
				_includePathWidget->addItem(path);
			}
			_includePathWidget->addItem("");

			_importPathWidget->clearItems();
			for (int i = 0; i < _script->importPathCount(); i++)
			{
				const BString& path = _script->importPath(i);
				_importPathWidget->addItem(path);
			}
			_importPathWidget->addItem("");

			if (BTreeItem* classItem = _treeWidget->addItem("Basic class"))
			{
				BMap<BString, BClass*>& classes = script->query("basic-classes");
				for (auto it = classes.begin(); it != classes.end(); it++)
				{
					BClass* cls = *it;
					BTreeItem* item = this->createTreeItem(cls);
					classItem->addChild(item);
				}
			}
			if (BTreeItem* classItem = _treeWidget->addItem("Registed Class"))
			{
				for (int i = 0; i < script->registedClassCount(); i++)
				{
					BClass* cls = script->registedClass(i);
					BTreeItem* item = this->createTreeItem(cls);
					classItem->addChild(item);
				}
			}
			if (BTreeItem* functionItem = _treeWidget->addItem("Registed Function"))
			{
				BString name;
				for (int i = 0; i < script->registedFunctionCount(); i++)
				{
					script->registedFunction(i, name);
					functionItem->addChild(name);
				}
			}
			if (BTreeItem* classItem = _treeWidget->addItem("Class"))
			{
				BMap<BString, BClass*> classes = script->query("classes");
				for (auto it = classes.begin(); it != classes.end(); it++)
				{
					BClass* cls = *it;
					BTreeItem* item = this->createTreeItem(cls);
					classItem->addChild(item);
				}
			}
		}
	}
}

void ScriptPropertyDialog::slotListItemClicked(BObject* object, const BValue& value)
{
	if (_itemEdit->asset() != value)
	{
		_itemEdit->setAsset(value);
	}
	else
	{
		if (BListItem* item = _itemEdit->asset())
		{
			_itemEdit->setParent(item->listWidget());
			_itemEdit->setRect(item->textArea());
			_itemEdit->setText(item->text());
			_itemEdit->setFocused(true);
			_itemEdit->show();

			BSize buttonSize = _itemEdit->centerRect().size().wrap(_browseButton->adaptSize());
			BRect buttonRect = _itemEdit->centerRect().align(Align_RightCenter, buttonSize);
			_browseButton->setRect(buttonRect);
		}
	}
}
void ScriptPropertyDialog::slotTargetEditFinished(BObject* object, const BValue& value)
{
	const BString& targetFileName = value;
	_script->setProperty("target", targetFileName);
	emit("script-info-changed", _script);
}
void ScriptPropertyDialog::slotItemEditFinished(BObject* object, const BValue& value)
{
	if (BListItem* item = _itemEdit->asset())
	{
		if (item->setText(_itemEdit->text()))
		{
			if (item->next() == 0 && item->text().size())
				item->listWidget()->addItem("");
			if (item->listWidget() == _includePathWidget)
			{
				applyIncludePaths();
			}
			if (item->listWidget() == _importPathWidget)
			{
				applyImportPaths();
			}
		}
	}
}
void ScriptPropertyDialog::slotItemEditActived(BObject* object, const BValue& value)
{
	if (value == false)
	{
		_itemEdit->hide();
	}
}
void ScriptPropertyDialog::slotBrowseButtonClicked(BObject* object, const BValue& value)
{
	if (_fileDialog.empty())
	{
		_fileDialog = new BFileDialog(this);
	}
	_fileDialog->setTitle("Choose Path");
	_fileDialog->setAttribFilter(Attrib_Folder);
	if (_fileDialog->execute())
	{
		const BString& fileName = _fileDialog->fileName();
		_itemEdit->setText(fileName);
	}
}
